{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "87ff3366-0142-4608-9595-53de065301c6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "嵌入数量: 5\n",
      "每个嵌入的维度: 1536\n",
      "查询嵌入维度: 1536\n"
     ]
    }
   ],
   "source": [
    "# 嵌入将一段文本创建成向量表示。这非常有用，因为它意味着我们可以在向量空间中思考文本，并且可以执行语义搜索等操作，在向量空间中寻找最相似的文本片段\n",
    "from pydantic import BaseModel, Field\n",
    "from typing import List, Dict, Optional\n",
    "import requests\n",
    "import numpy as np\n",
    "\n",
    "class Document(BaseModel):\n",
    "    \"\"\"接口，用于与文档进行交互。\"\"\"\n",
    "    page_content: str\n",
    "    lookup_str: str = \"\"\n",
    "    lookup_index: int = 0\n",
    "    metadata: Dict[str, str] = Field(default_factory=dict)\n",
    "\n",
    "    @property\n",
    "    def paragraphs(self) -> List[str]:\n",
    "        return self.page_content.split(\"\\n\\n\")\n",
    "\n",
    "    @property\n",
    "    def summary(self) -> str:\n",
    "        return self.paragraphs[0]\n",
    "\n",
    "    def lookup(self, string: str) -> str:\n",
    "        if string.lower() != self.lookup_str:\n",
    "            self.lookup_str = string.lower()\n",
    "            self.lookup_index = 0\n",
    "        else:\n",
    "            self.lookup_index += 1\n",
    "\n",
    "        lookups = [p for p in self.paragraphs if self.lookup_str in p.lower()]\n",
    "        if not lookups:\n",
    "            return \"No Results\"\n",
    "        elif self.lookup_index >= len(lookups):\n",
    "            return \"No More Results\"\n",
    "        else:\n",
    "            result_prefix = f\"(Result {self.lookup_index + 1}/{len(lookups)})\"\n",
    "            return f\"{result_prefix} {lookups[self.lookup_index]}\"\n",
    "\n",
    "class LaozhangEmbeddings:\n",
    "    def __init__(self, \n",
    "                 api_key: str,\n",
    "                 model: str = \"text-embedding-ada-002\",\n",
    "                 base_url: str = \"https://api.laozhang.ai/v1\"):\n",
    "        \n",
    "        self.api_key = api_key\n",
    "        self.model = model\n",
    "        self.base_url = base_url\n",
    "        \n",
    "    def embed_documents(self, texts: List[str]) -> List[List[float]]:\n",
    "        \"\"\"嵌入多个文档\"\"\"\n",
    "        if not texts:\n",
    "            return []\n",
    "            \n",
    "        headers = {\n",
    "            \"Authorization\": f\"Bearer {self.api_key}\",\n",
    "            \"Content-Type\": \"application/json\"\n",
    "        }\n",
    "        data = {\n",
    "            \"model\": self.model,\n",
    "            \"input\": texts\n",
    "        }\n",
    "        \n",
    "        try:\n",
    "            response = requests.post(\n",
    "                f\"{self.base_url}/embeddings\",\n",
    "                headers=headers,\n",
    "                json=data,\n",
    "                timeout=15\n",
    "            )\n",
    "            \n",
    "            # 处理API错误响应\n",
    "            if response.status_code != 200:\n",
    "                error_info = response.json().get(\"error\", {})\n",
    "                error_msg = error_info.get(\"message\", \"未知错误\")\n",
    "                raise ValueError(f\"API错误({response.status_code}): {error_msg}\")\n",
    "                \n",
    "            return [item['embedding'] for item in response.json()['data']]\n",
    "            \n",
    "        except requests.exceptions.RequestException as e:\n",
    "            raise Exception(f\"API请求失败: {str(e)}\")\n",
    "\n",
    "    def embed_query(self, text: str) -> List[float]:\n",
    "        \"\"\"嵌入单个查询\"\"\"\n",
    "        return self.embed_documents([text])[0]\n",
    "\n",
    "# 初始化嵌入模型\n",
    "embeddings_model = LaozhangEmbeddings(\n",
    "    api_key=\"sk-tAdNbV9aGTCr4fcE2d4b07Aa9f5c443bA7Fb3dE0Ff82F1A1\"  # 替换为你的API密钥\n",
    ")\n",
    "\n",
    "# 嵌入文档示例\n",
    "embeddings = embeddings_model.embed_documents([\n",
    "    \"Hi there!\",\n",
    "    \"Oh, hello!\",\n",
    "    \"What's your name?\",\n",
    "    \"My friends call me World\",\n",
    "    \"Hello World!\"\n",
    "])\n",
    "print(f\"嵌入数量: {len(embeddings)}\")\n",
    "print(f\"每个嵌入的维度: {len(embeddings[0])}\")\n",
    "\n",
    "# 嵌入查询示例\n",
    "query = \"What was the name mentioned in the conversation?\"\n",
    "query_embedding = embeddings_model.embed_query(query)\n",
    "print(f\"查询嵌入维度: {len(query_embedding)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "1b1108d3-3d66-4855-9d62-12107e3aca87",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "状态码: 200\n",
      "响应内容: {\"object\":\"list\",\"data\":[{\"object\":\"embedding\",\"index\":0,\"embedding\":[-0.0016492668,-0.013967778,0.0014286026,-0.018426776,-0.0074340086,0.01848304,-0.009769005,-0.02900459,-0.006118815,-0.0143124005,0.011456954,0.007286313,0.0013837665,-0.0118648745,-0.007230048,0.012891711,0.046924982,0.0006101232,0.017301477,-0.028681066,0.01059188,0.007142134,-0.0035816168,0.0012246422,-0.030045493,-0.014868017,0.0017714673,-0.03719114,-0.0030857818,0.0028220396,0.019158222,-0.028807662,-0.026739925,-0.029989228,-0.02339216,-0.008580407,-0.0037803024,-0.014235036,0.017835995,-0.00027912698,0.010430118,0.013194134,0.0056581455,-0.014291301,-0.0031983117,-0.008439745,0.011759378,-0.028343476,-0.02237939,0.016963888,0.010514515,0.0070225713,-0.012617419,-0.009761971,-0.01280028,0.0011956305,-0.008263917,0.002786874,0.013398095,-0.014657023,-0.02634607,-0.007103452,-0.012807313,0.024095472,0.0114991525,-0.007863029,0.0057319934,0.012666651,0.0089531625,0.0067166304,0.024039207,0.013173035,-0.0010936502,0.01158355,0.029595373,-0.0065935506,-0.005985186,-0.0124626905,-0.014368665,0.01401701,0.025699023,-0.013721619,-0.020227255,0.0025653308,0.016387172,0.008369414,0.00046462554,0.019453613,-0.0066427826,0.001254533,-0.000862876,0.014087341,0.0062524443,0.0073144455,-0.018961294,-0.0061399145,0.0045152637,0.034828015,-0.019144155,-0.032830607,-0.00573551,-0.008594474,0.014755487,-0.01777973,-0.00948768,0.004761423,-0.0022418073,-0.0015587154,0.024222068,0.007085869,-0.0342935,0.036065843,-0.0071843327,-0.023434358,0.0075465385,0.0013160728,-0.0067342133,-0.024264267,0.0015130001,-0.0012211256,0.0287092,0.0010883755,0.027823025,-0.01789226,0.0124626905,0.01201257,-0.013559857,-0.030411214,-0.0008316665,0.01115453,0.03136772,0.010183959,0.023251498,-0.0011692563,-0.022055866,0.00869997,-0.032380488,0.024278333,-0.03963867,-0.015782323,0.0025442315,0.032718077,-0.01182971,-0.0064458554,-0.011604649,0.015388468,0.03240862,0.005521,-0.0010593638,-0.02361722,0.008285017,-0.010409019,0.011801577,0.009508779,-0.008594474,0.019959997,0.0043570185,-0.010577814,-0.015726058,-0.0018110286,0.007511373,0.012223564,0.004065144,-0.0198334,0.0040756934,0.030045493,0.00012758521,0.008889865,-0.005345172,-0.0187081,-0.012919843,0.021422885,-0.040257584,0.027260376,0.010409019,0.017188948,-0.0075254394,0.013932613,-0.009951866,-0.008840633,-0.016457504,0.019692738,0.0342091,0.028456006,-0.00009945272,-0.01822985,0.009726807,-0.009234488,0.0044871313,-0.025389567,0.019931864,0.016119912,0.004768456,-0.0033090834,-0.6913839,0.009431415,0.0071140015,-0.0034673286,0.032211695,0.038232043,0.04892239,0.011182662,-0.032324225,0.004532846,0.0055245166,0.01424207,-0.010190992,-0.014094374,-0.008074023,0.0064036567,0.011759378,-0.023462491,0.00066902564,0.027091581,-0.014600758,0.014431964,0.008481944,0.012617419,-0.0032457854,-0.00006197938,-0.0022224663,-0.014298335,0.003970197,-0.010690344,-0.024320532,0.010451217,0.014382732,0.006143431,0.034124702,-0.015711991,-0.017596869,0.0071562002,0.0002745115,0.03634717,-0.009579111,-0.0077715986,0.031198924,0.019130088,0.0029785268,0.013461393,0.0065724514,0.00012417854,-0.0013758542,-0.0046594427,0.0011112331,-0.001330139,-0.012568187,0.0054999003,-0.0045750453,-0.012230597,0.013925579,-0.011063099,-0.000428361,0.0055315495,-0.008193586,-0.0012835446,-0.008362381,-0.009072726,-0.041411016,0.017906325,-0.017442139,0.026008481,0.0042339386,-0.0046277936,-0.0037873355,-0.0034233716,-0.016626298,-0.01081694,0.017610935,0.03125519,0.021901138,-0.0077926978,-0.0035341433,0.005320556,-0.00051034085,0.00033517217,-0.008531176,0.0058691395,0.03193037,-0.0049794493,-0.007574671,-0.00739181,0.01602145,0.014052175,0.025516162,0.017484339,0.0039315145,-0.003595683,0.016119912,0.004328886,0.0013837665,0.0057249605,0.025009777,-0.011527285,0.0005310006,-0.0004962746,0.0012378292,-0.004824721,-0.0068291603,0.011949272,0.00694169,0.02900459,0.024728453,-0.009157123,-0.018848764,-0.015205607,-0.006059034,-0.009164156,0.00064616796,-0.03994813,0.006741246,0.014052175,0.014417898,-0.019552076,0.013538757,0.008052924,0.020466382,0.002240049,-0.0024317016,0.0089531625,-0.012891711,-0.01714675,-0.016949821,-0.02084617,0.006055517,-0.013461393,0.010394952,-0.03148025,0.009410316,-0.0046664756,0.024925381,-0.021802675,0.013440294,-0.026022548,-0.0037803024,-0.0034497457,0.009508779,0.012849512,0.01180861,-0.02050858,-0.019777136,-0.013672387,-0.011576517,0.020635176,-0.018243916,-0.0046594427,-0.023124902,-0.0023068637,-0.0027024767,-0.02990483,-0.0019270751,-0.022548186,-0.018525241,-0.008939097,-0.0014769554,0.027218178,-0.015050879,0.0014092616,-0.0077012675,0.00079738005,-0.0209587,0.013313698,-0.0038928324,-0.025206706,-0.009628342,-0.0030717156,-0.0035622758,0.024095472,0.004026462,0.008369414,0.00032066635,-0.00838348,0.0038576669,-0.022294993,0.008826567,0.011674981,-0.0032897422,0.006864326,0.023715684,0.01737181,0.0109013375,0.010331655,-0.010528582,0.008721069,-0.016344972,-0.008854699,-0.007848963,0.005774192,-0.0019428997,0.012026637,0.006551352,0.0014945382,0.008081056,0.008306116,0.024348665,-0.0073425784,-0.005433086,-0.0011332115,0.021436952,-0.022970174,0.009684607,-0.014952415,0.0068819085,0.019566143,0.009290753,-0.043239627,-0.027893357,-0.0063368417,0.026149143,0.02107123,-0.003463812,0.00021879599,-0.008102155,0.0063790404,0.010760675,-0.009396249,-0.0038963489,-0.010401986,-0.0038506337,0.0038189846,0.01412954,0.040820234,0.021957403,-0.030214287,-0.01822985,0.01699202,0.01036682,-0.00026022547,0.020635176,0.011027933,0.010120661,-0.024840983,0.03930108,0.019706804,0.012610385,0.011590583,0.033393256,-0.0030383081,0.01953801,0.0021240024,0.032099165,-0.00040220658,-0.010071429,0.0076872013,-0.0024246685,0.010514515,0.0009890326,-0.0136583205,0.033702716,-0.011063099,-0.010866172,0.01822985,0.021535415,0.047797088,0.01739994,0.009558011,-0.0006105628,-0.001713444,0.008390513,-0.006364974,0.009944833,-0.0012474998,0.0045539457,-0.028188748,-0.01014176,-0.015515065,0.009867469,-0.007673135,0.018961294,0.013032373,0.006326292,-0.0040018456,0.02365942,-0.01115453,-0.0034145801,-0.03297127,0.022168396,0.0019218003,0.0075817043,-0.020522647,-0.03468735,0.0032264441,-0.0031086395,0.0001409921,-0.01739994,-0.022998305,0.01976307,-0.0198334,0.014171738,0.022463787,0.004849337,0.0019534493,0.0004597903,-0.003871733,0.00618563,-0.0023736784,-0.006350908,-0.02282951,0.008425679,-0.007975559,-0.022984238,-0.021324422,0.014150639,-0.0024703837,0.01379195,-0.0098604355,-0.017653134,0.00091606396,0.0061785965,0.009290753,-0.020227255,0.0021169693,0.022731047,0.011006834,-0.027527634,-0.0209587,-0.022449723,0.001361788,0.028118417,0.029426578,0.016007382,0.020072527,-0.009719773,-0.011682014,-0.023631286,-0.020269454,0.010310555,-0.010838039,0.005774192,-0.0032141362,0.008397547,-0.017835995,0.0068748756,0.02474252,-0.0015736608,-0.008784368,0.01390448,0.00618563,-0.011330358,0.0049548335,0.013391062,0.015655726,0.008242818,-0.0009819994,0.0013037648,0.01687949,0.0109013375,-0.0139466785,-0.008010725,0.015500998,-0.0086648045,0.017132683,0.00138025,0.026542999,-0.0034374378,0.011168596,0.010008131,-0.01059188,0.025417699,0.00080968806,0.0002773687,-0.00053627545,-0.0015745399,-0.0010347479,0.017709399,0.01225873,-0.0023807115,-0.02499571,0.0097830715,0.0107466085,-0.0209587,-0.015486932,-0.001299369,0.030383082,-0.015937053,-0.008390513,-0.018103253,-0.008770302,-0.02522077,-0.04112969,0.0005802325,-0.010598913,-0.013953712,-0.0364597,-0.023434358,-0.012188398,-0.027330708,-0.0165419,-0.00695224,-0.024039207,-0.012814346,-0.01444603,0.024531525,0.0068819085,0.02107123,0.022294993,0.0028659967,0.016344972,-0.012863578,0.0003758324,-0.012216531,-0.01401701,0.0058269408,0.011703113,0.0037873355,0.0008562825,0.0003083584,-0.0063544246,0.010802873,0.008903931,-0.004167124,-0.023589088,0.011020901,0.004255038,0.0026128043,0.012490823,-0.0150649445,-0.006600584,0.0014549769,-0.017385874,0.0037732692,0.0040897597,0.004944284,0.008580407,-0.020325718,0.027752696,-0.023743816,-0.003388206,0.031395853,-0.012096968,0.01334183,-0.0055631986,0.008896898,0.0013995911,-0.0014136573,0.023012372,-0.007813797,-0.011428821,-0.0013714585,-0.031452116,0.028160615,0.008320182,-0.0098604355,0.0024440095,-0.018525241,-0.011717179,-0.000045797704,0.00727928,-0.024123605,0.021605747,-0.014368665,-0.006864326,-0.039863728,-0.029173385,-0.027316641,0.008109189,0.007448075,0.0050919796,-0.024672188,0.010430118,0.007135101,-0.036319036,0.0004975933,-0.036403432,-0.012026637,0.010162859,-0.008179519,0.018384578,0.005478801,-0.013988878,-0.031874105,-0.009804171,-0.012511922,-0.042198725,0.011105298,-0.019805267,0.024053274,0.008896898,0.03297127,-0.0042163557,0.012329061,0.008622606,0.0012009054,-0.003018967,-0.021155627,0.0020870785,-0.013510625,0.028188748,0.025980348,-0.0025319236,0.009150091,0.007588737,-0.0007358403,0.017934458,-0.009536912,-0.006473988,-0.008474911,-0.006168047,0.0028220396,0.0019059757,-0.003959647,0.017568735,-0.014516361,-0.019791203,0.029932963,-0.001204422,0.0006830919,-0.0065935506,0.010739575,-0.016851358,-0.0048669195,0.009776038,-0.007553572,0.01182971,-0.017203014,-0.034040306,-0.0023156551,0.014059208,-0.0022347742,0.01848304,-0.0069733392,0.014361633,-0.010535615,0.019720871,-0.0353344,-0.0141787715,-0.0047368067,-0.016415304,-0.005109562,-0.0051130787,0.021647945,-0.010198025,0.018764365,0.011386623,-0.02810435,0.005162311,-0.013376996,-0.017118616,-0.006273544,-0.009607243,0.029257782,0.02249192,0.019917797,0.032943137,-0.0017371809,-0.032943137,-0.020438248,-0.0079333605,-0.019580208,0.032577414,0.01953801,-0.0077012675,-0.004029978,0.017709399,0.023898544,-0.0051306617,-0.011485087,-0.0037873355,0.02050858,0.0019552077,-0.021929272,-0.002786874,-0.046756186,0.020044394,0.0006606738,-0.01002923,-0.018257981,-0.00237192,-0.000514297,0.0088125,-0.02934218,0.016865423,0.018876897,-0.030776937,0.0055139665,-0.0011885974,-0.020705508,0.003432163,-0.0077645653,0.03719114,-0.016949821,0.004673509,0.02837161,-0.0021732342,-0.016865423,0.0015147584,-0.01590892,0.030495612,-0.032267958,0.0050743967,-0.0037662361,0.012188398,0.005897272,0.015290005,-0.024615923,-0.017976657,-0.010866172,-0.0004386909,0.022323126,0.008995362,0.0068221274,-0.011885975,-0.010556715,-0.0043077865,-0.01728741,-0.032802474,0.0030576494,-0.00097232894,-0.031339586,0.002604013,0.0018180617,0.001016286,0.0024123604,-0.018694036,0.0057425434,0.013081605,-0.03696608,0.011597617,-0.0074691745,0.0019569658,-0.011724212,0.00519396,-0.015740125,-0.015233739,0.019509878,-0.03342139,-0.020691441,-0.02499571,-0.012455657,0.017695332,0.007813797,-0.008622606,0.0029767684,-0.012272796,-0.0022330158,0.0038928324,-0.0138130495,0.00573551,-0.015107144,0.009698674,-0.0040897597,-0.014628891,0.010711443,0.008847666,0.016963888,0.0066990475,-0.017793795,-0.005250225,-0.0057636425,0.011042,-0.005253741,-0.010247257,-0.028751398,-0.002936328,0.0035024942,0.015768256,0.0011411238,-0.012054769,-0.003632607,-0.013243367,0.00019110308,0.019186353,-0.012765114,0.0030453412,-0.02889206,-0.00057407847,-0.0152196735,-0.011970372,0.004462515,0.026177276,0.00539792,-0.022154331,-0.0264586,0.0077645653,-0.059078217,-0.021211892,-0.002779841,0.019495811,0.015416601,0.0017046527,-0.017329609,0.02129629,0.016893556,0.030551877,-0.014474163,-0.012251697,0.013834149,-0.020002196,0.011252994,-0.009698674,-0.037556864,-0.0057636425,0.019988129,0.027218178,0.01412954,0.0077012675,-0.0050814296,-0.010732543,-0.000004522764,0.011604649,0.010219124,-0.026613329,-0.008805468,-0.00892503,-0.011456954,0.012645551,-0.0068994914,-0.014115473,-0.02237939,-0.0023701617,-0.009726807,0.012476756,-0.042564448,0.000862876,-0.0114217885,-0.022646649,0.01147102,0.008292049,0.010359787,0.031311452,0.010753642,-0.013841182,-0.012293895,0.0060695834,-0.019734938,-0.0063966233,-0.0042902036,-0.011379589,-0.022098066,-0.012793247,0.0066673984,-0.0111123305,0.0028466557,-0.018356446,-0.005703861,0.0058691395,0.019341081,0.017639067,-0.026782123,-0.00033275454,-0.020818038,-0.010936503,0.0075254394,-0.011682014,0.011386623,-0.0061082654,0.010282422,0.010064396,-0.0025618142,-0.013222267,-0.027752696,0.012314995,-0.011006834,0.013489526,0.2018787,-0.00004214378,-0.0068291603,0.024390863,0.00804589,0.00010511219,0.009389216,0.012708849,0.0015033296,0.022027735,0.025699023,0.0070999353,0.0040334947,0.010198025,0.0035939247,0.017062351,-0.023631286,-0.027668297,0.0013881623,-0.021647945,0.013798983,-0.024601856,-0.0009863952,0.00044154812,0.047656428,0.004965383,-0.00924152,0.0007868304,0.02922965,-0.012870611,-0.029595373,-0.0013978328,0.0027270927,-0.0037345872,-0.02039605,-0.008749202,-0.0009802412,0.019481745,0.017568735,-0.01225873,0.0073285117,-0.006048484,0.013890414,-0.015627595,0.00059825485,0.016105847,0.0049302178,-0.01379195,0.0013600298,0.013806016,-0.041720472,-0.0052220924,0.0126947835,0.014839885,0.020381983,0.006797511,0.04394294,-0.017442139,-0.0065232194,0.015500998,-0.024503393,0.013784917,-0.03240862,0.021352556,-0.027119715,0.007820831,-0.01557133,-0.002058946,0.012870611,0.0025741223,0.0063016764,-0.024545591,-0.00019516911,-0.00050990126,-0.021830807,-0.016837291,0.02526297,0.019003492,0.023181166,0.0037908521,-0.002591705,-0.0054049534,0.008362381,-0.016724762,-0.003068199,-0.029285915,0.0044836146,0.004473065,-0.009508779,0.006037934,-0.02327963,-0.020818038,-0.025248904,-0.031789705,0.005471768,0.036853552,-0.0022154332,0.019509878,0.0042902036,-0.0075395056,-0.013918546,0.010549681,0.03454669,0.017540604,-0.0035675506,0.028723266,-0.020269454,-0.0019393831,-0.009051627,-0.005703861,-0.01302534,-0.038232043,0.010247257,-0.0079333605,-0.002880063,-0.0016026724,-0.0019059757,-0.011914107,0.0014532186,-0.004764939,0.019580208,-0.0019938897,-0.004726257,0.009382183,0.0019745487,0.0022681814,-0.017048284,-0.010690344,0.022084,-0.024615923,-0.0017952041,-0.014171738,0.01467109,-0.0055702315,-0.013440294,-0.0017837753,-0.003871733,-0.00031077603,-0.028470073,0.0006197938,0.018525241,-0.022449723,-0.02055078,0.0069241077,0.0013424469,-0.019327017,0.038147647,-0.010894304,-0.0123079615,-0.0068115774,-0.016963888,-0.022224661,-0.015107144,-0.00097144983,0.024981646,-0.0046348264,-0.02889206,-0.036994215,0.012265762,-0.0087421695,-0.028976457,-0.0059465035,0.045630887,-0.0052607744,-0.013032373,-0.010521549,-0.18623704,0.01976307,0.020522647,-0.017315544,0.008334248,-0.002948636,0.027232245,-0.016485635,-0.0093399845,0.0033671067,0.019439546,0.0063227755,-0.02339216,-0.0046137273,-0.0024703837,-0.0007929844,-0.007008505,-0.008967229,0.015261873,0.028301278,0.025558362,-0.024151737,0.0051658275,-0.012533021,0.0028255563,0.0009863952,-0.006776412,0.025614627,0.01834238,-0.0038998656,-0.01739994,-0.0019499328,0.020930568,-0.008749202,0.0035288683,-0.0020272972,0.01455856,-0.018046988,-0.0012061802,0.0073144455,-0.0030594075,0.03451856,-0.0065865177,-0.007898195,-0.00248445,0.010416052,0.0076098368,0.01597925,0.024981646,-0.027204111,0.0059429873,-0.0076661017,0.01489615,-0.022970174,0.022646649,0.00297501,-0.024826916,0.0005811116,0.01848304,0.009192289,-0.004873953,-0.041636076,0.019664606,0.0045222966,-0.022970174,-0.013510625,-0.018426776,-0.004982966,-0.02402514,0.0088125,0.0010066155,-0.010268357,0.04121409,-0.017990723,0.019594274,0.0012835446,-0.022069933,0.004655926,-0.0059078215,0.0028519304,-0.011534318,0.043999203,0.008910964,0.018243916,0.007968526,0.011034966,-0.0013275016,0.01147102,0.00232093,-0.014009977,0.033449523,0.00046198812,-0.00750434,-0.009987032,0.015388468,0.011217828,-0.0022154332,0.010894304,0.0067904782,-0.00750434,-0.0077575324,-0.0017310269,-0.023110835,0.017596869,0.0145444935,-0.0062313452,0.014340533,0.03724741,0.016007382,-0.0025512646,-0.033027537,-0.011260026,0.023378093,0.010401986,0.017076418,0.027569834,0.0052431915,-0.02934218,-0.0030523743,-0.013264466,0.030101757,-0.0039104153,-0.007191366,0.016162112,0.009255587,-0.011548384,-0.10347127,-0.05314226,0.01377085,0.05857183,-0.007743466,0.028540405,0.01822985,0.026585197,-0.0058832057,0.026500799,-0.030101757,-0.015965184,-0.017062351,-0.012708849,-0.011006834,0.0075395056,0.006846743,-0.009895601,-0.0059570535,0.043549083,-0.015894853,-0.0065337694,0.0052924235,-0.030298684,-0.0042374553,-0.0079333605,-0.036206506,0.037669394,0.017414007,-0.00804589,0.0012536538,-0.0210009,0.01773753,-0.043464687,-0.009543945,-0.0042022895,-0.019988129,-0.020986833,0.052382685,-0.0072722468,0.02361722,0.013299632,0.0022980722,-0.016513769,0.019228552,-0.02713378,0.0017617968,0.0068819085,-0.0148539515,-0.028273147,-0.022294993,0.0069487235,0.0072019156,-0.014284268,0.0054893508,0.008777334,0.022252794,0.031086395,-0.016935755,0.0004800105,-0.004873953,-0.00071605964,0.011639815,0.021844873,-0.010401986,-0.00027143452,-0.030495612,-0.006997955,0.0073425784,-0.01568386,0.010261323,0.012047736,-0.0056581455,0.029961094,-0.02582562,0.02593815,-0.03840084,-0.010043297,0.032267958,-0.016555967,-0.011928173,-0.00089188764,0.0089531625,-0.025980348,0.031649042,-0.0070612533,-0.013848215,-0.00013286005,0.0021310356,-0.020818038,-0.0020413634,0.027091581,0.029201517,-0.022463787,-0.040960897,0.019889666,-0.009881535,-0.005767159,0.0089742625,0.0055456157,-0.0138130495,-0.036769155,-0.06374821,0.017835995,-0.0058867224,0.003840084,0.0084327115,0.025558362,-0.007940394,-0.008285017,-0.0008734257,0.016949821,-0.014087341,0.019214487,-0.0009494713,-0.010697377,-0.00827095,-0.00695224,0.02185894,0.025530228,0.015275938,0.018694036,0.00358865,-0.013531725,0.01313787,0.0010048571,-0.011548384,0.0019657572,-0.009121958,0.012582253,-0.0072370814,-0.0139466785,0.007743466,-0.021155627,-0.0051728603,0.015402535,-0.0092626205,-0.0021538932,-0.01687949,0.014087341,0.015852654,0.0025231321,-0.011731246,-0.020353852,0.0069065248,-0.034377895,-0.01863777,0.010648145,-0.0198334,0.018370511,0.011801577,-0.0077715986,0.0085874405,0.011674981,-0.016176177,-0.016935755,-0.006653332,-0.023631286,-0.0024317016,-0.0029503943,0.0026848938,-0.006853776,0.023476558,0.016190244,0.041495413,0.013686453,0.013721619,0.0043605347,-0.014136573,-0.00539792,0.013932613,-0.010261323,-0.014657023,-0.010767708,0.027035316,0.0011938723,0.018243916,-0.002885338,-0.004997032,0.0035446929,0.022112131,0.01920042,-0.0022769729,0.020789905,-0.044815045,0.018356446,0.019003492,0.014474163,-0.010176926,-0.005394404,-0.0052361586,-0.0030154507,-0.02111343,0.00358865,-0.0018110286,0.0016466294,-0.0042163557,0.011119364,-0.0058585894,-0.0071069687,0.024672188,0.014825819,0.011773445,0.0066462993,0.006368491,0.0015631111,0.013032373,-0.008854699,-0.02406734,-0.03795072,-0.0033336992,0.021240026,0.0069874055,0.0022558735,0.006885425,0.008524142,-0.0075957705,0.012962041,-0.020297587,0.0017811379,-0.021535415,0.016274642,-0.0014004702,0.019931864,0.029989228,0.0017890501,0.013777884,-0.0070401537,0.011042,-0.014228003,-0.0006914437,0.016415304,0.014727355,-0.002579397,-0.026753992,-0.026669594,-0.019720871,0.001142003,0.0007028725,0.008671838,-0.023068637,0.06138508,0.032915007,-0.011703113,0.010359787,0.011323324,0.008348314,0.012336094,0.024222068,-0.0018567439,-0.008109189,0.019791203,0.0076309363,0.01047935,-0.0058199074,-0.019341081,0.016710695,-0.0032405104,0.010514515,0.0031701792,0.006294643,0.010078462,-0.0046277936,0.025094176,0.0045469124,-0.015430667,-0.017540604,0.030889466,-0.0085874405,-0.008460844,-0.010486383,0.017076418,0.0054225363,-0.028062152,-0.032718077,0.018468976,-0.013595022,0.004367568,-0.01642937,-0.0030734737,0.00079474266,0.016049583,0.02922965,-0.047768958,-0.027091581,0.0077786315,0.0032915005,-0.012490823,-0.010535615,0.00039737133]}],\"model\":\"text-embedding-ada-002\",\"usage\":{\"prompt_tokens\":1,\"total_tokens\":1,\"prompt_tokens_details\":{},\"completion_tokens_details\":{},\"input_tokens\":0,\"output_tokens\":0,\"input_tokens_details\":null}}\n"
     ]
    }
   ],
   "source": [
    "# 测试老张API端点可用性：\n",
    "import requests\n",
    "\n",
    "response = requests.post(\n",
    "    \"https://api.laozhang.ai/v1/embeddings\",\n",
    "    headers={\"Authorization\": \"Bearer sk-tAdNbV9aGTCr4fcE2d4b07Aa9f5c443bA7Fb3dE0Ff82F1A1\"},\n",
    "    json={\"model\": \"text-embedding-ada-002\", \"input\": [\"test\"]},\n",
    "    timeout=10\n",
    ")\n",
    "print(\"状态码:\", response.status_code)\n",
    "print(\"响应内容:\", response.text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ac51dbf2-4b60-4f79-9589-8b128389c179",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Created a chunk of size 215, which is longer than the specified 200\n",
      "Created a chunk of size 232, which is longer than the specified 200\n",
      "Created a chunk of size 242, which is longer than the specified 200\n",
      "Created a chunk of size 219, which is longer than the specified 200\n",
      "Created a chunk of size 304, which is longer than the specified 200\n",
      "Created a chunk of size 205, which is longer than the specified 200\n",
      "Created a chunk of size 332, which is longer than the specified 200\n",
      "Created a chunk of size 215, which is longer than the specified 200\n",
      "Created a chunk of size 203, which is longer than the specified 200\n",
      "Created a chunk of size 281, which is longer than the specified 200\n",
      "Created a chunk of size 201, which is longer than the specified 200\n",
      "Created a chunk of size 250, which is longer than the specified 200\n",
      "Created a chunk of size 325, which is longer than the specified 200\n",
      "Created a chunk of size 242, which is longer than the specified 200\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.2.6\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 5/5 [00:21<00:00,  4.34s/it]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n",
      "And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n"
     ]
    }
   ],
   "source": [
    "\"\"\"存储和搜索非结构化数据最常见的方法之一是将其嵌入并存储生成的嵌入向量，然后在查询时将非结构化查询进行嵌入，并检索与嵌入查询“最相似”的嵌入向量。\n",
    "向量存储库负责为您存储已经过嵌入处理的数据并执行向量搜索\n",
    "\"\"\"\n",
    "from langchain.document_loaders import TextLoader\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "from langchain.vectorstores import Chroma\n",
    "from tqdm import tqdm\n",
    "from typing import List\n",
    "import requests\n",
    "import numpy as np\n",
    "print(np.__version__)\n",
    "\n",
    "class LaozhangEmbeddings:\n",
    "    def __init__(self, \n",
    "                 api_key: str,\n",
    "                 model: str = \"text-embedding-ada-002\",\n",
    "                 base_url: str = \"https://api.laozhang.ai/v1\"):\n",
    "        \n",
    "        self.api_key = api_key\n",
    "        self.model = model\n",
    "        self.base_url = base_url\n",
    "        \n",
    "    def embed_documents(self, texts: List[str]) -> List[List[float]]:\n",
    "        \"\"\"嵌入多个文档\"\"\"\n",
    "        if not texts:\n",
    "            return []\n",
    "            \n",
    "        headers = {\n",
    "            \"Authorization\": f\"Bearer {self.api_key}\",\n",
    "            \"Content-Type\": \"application/json\"\n",
    "        }\n",
    "        data = {\n",
    "            \"model\": self.model,\n",
    "            \"input\": texts\n",
    "        }\n",
    "        \n",
    "        try:\n",
    "            response = requests.post(\n",
    "                f\"{self.base_url}/embeddings\",\n",
    "                headers=headers,\n",
    "                json=data,\n",
    "                timeout=60\n",
    "            )\n",
    "            \n",
    "            # 处理API错误响应\n",
    "            if response.status_code != 200:\n",
    "                error_info = response.json().get(\"error\", {})\n",
    "                error_msg = error_info.get(\"message\", \"未知错误\")\n",
    "                raise ValueError(f\"API错误({response.status_code}): {error_msg}\")\n",
    "                \n",
    "            return [item['embedding'] for item in response.json()['data']]\n",
    "            \n",
    "        except requests.exceptions.RequestException as e:\n",
    "            raise Exception(f\"API请求失败: {str(e)}\")\n",
    "\n",
    "    def embed_query(self, text: str) -> List[float]:\n",
    "        \"\"\"嵌入单个查询\"\"\"\n",
    "        return self.embed_documents([text])[0]\n",
    "\n",
    "\n",
    "# 加载长文本\n",
    "raw_documents = TextLoader('data/state_of_the_union.txt').load()\n",
    "# 实例化文本分割器\n",
    "text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=0)\n",
    "# 分割文本\n",
    "documents = text_splitter.split_documents(raw_documents)\n",
    "# 初始化嵌入模型\n",
    "embeddings_model = LaozhangEmbeddings(api_key=\"sk-tAdNbV9aGTCr4fcE2d4b07Aa9f5c443bA7Fb3dE0Ff82F1A1\")\n",
    "\n",
    "# 将分割后的文本，使用嵌入模型获取嵌入向量，并存储在 Chroma 中\n",
    "# db = Chroma.from_documents(documents, embeddings_model)\n",
    "# 分批处理文档（每批50个）\n",
    "batch_size = 50\n",
    "db = Chroma.from_documents(documents[:batch_size], embeddings_model)\n",
    "\n",
    "for i in tqdm(range(batch_size, len(documents), batch_size)):\n",
    "    batch = documents[i:i+batch_size]\n",
    "    db.add_documents(batch)\n",
    "\n",
    "# 使用文本进行语义相似度搜索\n",
    "query = \"What did the president say about Ketanji Brown Jackson\"\n",
    "docs = db.similarity_search(query)\n",
    "print(docs[0].page_content)\n",
    "\n",
    "# 使用嵌入向量进行语义相似度搜索\n",
    "embedding_vector = embeddings_model.embed_query(query)\n",
    "docs = db.similarity_search_by_vector(embedding_vector)\n",
    "print(docs[0].page_content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "e84e2cec-70e2-44bf-a83e-a4fa8eb3016e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "200\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "response = requests.get(\"https://api.laozhang.ai\", timeout=10)\n",
    "print(response.status_code)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "16187e3a-4c9f-4ebb-ab54-09862254c7dd",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Created a chunk of size 215, which is longer than the specified 200\n",
      "Created a chunk of size 232, which is longer than the specified 200\n",
      "Created a chunk of size 242, which is longer than the specified 200\n",
      "Created a chunk of size 219, which is longer than the specified 200\n",
      "Created a chunk of size 304, which is longer than the specified 200\n",
      "Created a chunk of size 205, which is longer than the specified 200\n",
      "Created a chunk of size 332, which is longer than the specified 200\n",
      "Created a chunk of size 215, which is longer than the specified 200\n",
      "Created a chunk of size 203, which is longer than the specified 200\n",
      "Created a chunk of size 281, which is longer than the specified 200\n",
      "Created a chunk of size 201, which is longer than the specified 200\n",
      "Created a chunk of size 250, which is longer than the specified 200\n",
      "Created a chunk of size 325, which is longer than the specified 200\n",
      "Created a chunk of size 242, which is longer than the specified 200\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.2.6\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 13/13 [00:11<00:00,  1.18it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Because I know there is simply nothing beyond our capacity. \n",
      "\n",
      "We are the only nation on Earth that has always turned every crisis we have faced into an opportunity.\n",
      "Because I know there is simply nothing beyond our capacity. \n",
      "\n",
      "We are the only nation on Earth that has always turned every crisis we have faced into an opportunity.\n"
     ]
    }
   ],
   "source": [
    "\"\"\"存储和搜索非结构化数据最常见的方法之一是将其嵌入并存储生成的嵌入向量，然后在查询时将非结构化查询进行嵌入，并检索与嵌入查询“最相似”的嵌入向量。\n",
    "向量存储库负责为您存储已经过嵌入处理的数据并执行向量搜索（用多线程加速）\n",
    "\"\"\"\n",
    "from langchain.document_loaders import TextLoader\n",
    "from langchain.text_splitter import CharacterTextSplitter\n",
    "from langchain.vectorstores import Chroma\n",
    "from tqdm import tqdm\n",
    "from typing import List\n",
    "import requests\n",
    "from concurrent.futures import ThreadPoolExecutor\n",
    "import numpy as np\n",
    "print(np.__version__)\n",
    "\n",
    "class LaozhangEmbeddings:\n",
    "    def __init__(self, \n",
    "                 api_key: str,\n",
    "                 model: str = \"text-embedding-ada-002\",\n",
    "                 base_url: str = \"https://api.laozhang.ai/v1\"):\n",
    "        \n",
    "        self.api_key = api_key\n",
    "        self.model = model\n",
    "        self.base_url = base_url\n",
    "        \n",
    "    def embed_documents(self, texts: List[str]) -> List[List[float]]:\n",
    "        \"\"\"嵌入多个文档\"\"\"\n",
    "        if not texts:\n",
    "            return []\n",
    "            \n",
    "        headers = {\n",
    "            \"Authorization\": f\"Bearer {self.api_key}\",\n",
    "            \"Content-Type\": \"application/json\"\n",
    "        }\n",
    "        data = {\n",
    "            \"model\": self.model,\n",
    "            \"input\": texts\n",
    "        }\n",
    "        \n",
    "        try:\n",
    "            response = requests.post(\n",
    "                f\"{self.base_url}/embeddings\",\n",
    "                headers=headers,\n",
    "                json=data,\n",
    "                timeout=60\n",
    "            )\n",
    "            \n",
    "            # 处理API错误响应\n",
    "            if response.status_code != 200:\n",
    "                error_info = response.json().get(\"error\", {})\n",
    "                error_msg = error_info.get(\"message\", \"未知错误\")\n",
    "                raise ValueError(f\"API错误({response.status_code}): {error_msg}\")\n",
    "                \n",
    "            return [item['embedding'] for item in response.json()['data']]\n",
    "            \n",
    "        except requests.exceptions.RequestException as e:\n",
    "            raise Exception(f\"API请求失败: {str(e)}\")\n",
    "\n",
    "    def embed_query(self, text: str) -> List[float]:\n",
    "        \"\"\"嵌入单个查询\"\"\"\n",
    "        return self.embed_documents([text])[0]\n",
    "\n",
    "\n",
    "# 加载长文本\n",
    "raw_documents = TextLoader('data/state_of_the_union.txt').load()\n",
    "# 实例化文本分割器\n",
    "text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=0)\n",
    "# 分割文本\n",
    "documents = text_splitter.split_documents(raw_documents)\n",
    "# 初始化嵌入模型\n",
    "embeddings_model = LaozhangEmbeddings(api_key=\"sk-tAdNbV9aGTCr4fcE2d4b07Aa9f5c443bA7Fb3dE0Ff82F1A1\")\n",
    "\n",
    "def process_batch(batch):\n",
    "    db.add_documents(batch)\n",
    "\n",
    "batch_size = 20\n",
    "db = Chroma.from_documents(documents[:batch_size], embeddings_model)\n",
    "batches = [documents[i:i + batch_size] for i in range(0, len(documents), batch_size)]\n",
    "# 并行处理（加速大批量数据）\n",
    "with ThreadPoolExecutor(max_workers=4) as executor:  # 4个线程\n",
    "    list(tqdm(executor.map(process_batch, batches), total=len(batches)))\n",
    "\n",
    "# 使用文本进行语义相似度搜索\n",
    "query = \"What has always turned every crisis we have faced into an opportunity\"\n",
    "docs = db.similarity_search(query)\n",
    "print(docs[0].page_content)\n",
    "\n",
    "# 使用嵌入向量进行语义相似度搜索\n",
    "embedding_vector = embeddings_model.embed_query(query)\n",
    "docs = db.similarity_search_by_vector(embedding_vector)\n",
    "print(docs[0].page_content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b6018f97-a201-463e-b982-23bca93da41d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "page_content='Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and' metadata={'start_index': 0}\n",
      "page_content='of Congress and the Cabinet. Justices of the Supreme Court. My fellow Americans.' metadata={'start_index': 82}\n",
      "<class 'list'>\n",
      "<class 'langchain_core.documents.base.Document'>\n",
      "page_content='Madam Speaker, Madam Vice President, our First Lady and Second Gentleman. Members of Congress and' metadata={'document': 1, 'start_index': 0}\n",
      "['cpp', 'go', 'java', 'kotlin', 'js', 'ts', 'php', 'proto', 'python', 'rst', 'ruby', 'rust', 'scala', 'swift', 'markdown', 'latex', 'html', 'sol', 'csharp', 'cobol', 'c', 'lua', 'perl', 'haskell']\n",
      "13\n",
      "[Document(page_content='<!DOCTYPE html>\\n<html>'), Document(page_content='<head>\\n        <title>🦜️🔗 LangChain</title>'), Document(page_content='<style>\\n            body {\\n                font-family: Aria'), Document(page_content='l, sans-serif;\\n            }\\n            h1 {'), Document(page_content='color: darkblue;\\n            }\\n        </style>\\n    </head'), Document(page_content='>'), Document(page_content='<body>'), Document(page_content='<div>\\n            <h1>🦜️🔗 LangChain</h1>'), Document(page_content='<p>⚡ Building applications with LLMs through composability ⚡'), Document(page_content='</p>\\n        </div>'), Document(page_content='<div>\\n            As an open source project in a rapidly dev'), Document(page_content='eloping field, we are extremely open to contributions.'), Document(page_content='</div>\\n    </body>\\n</html>')]\n"
     ]
    }
   ],
   "source": [
    "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
    "from langchain.text_splitter import Language\n",
    "\n",
    "# 加载待分割长文本\n",
    "with open('data/state_of_the_union.txt') as f:\n",
    "    state_of_the_union = f.read()\n",
    "\n",
    "text_splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size = 100,\n",
    "    chunk_overlap  = 20,\n",
    "    length_function = len,\n",
    "    add_start_index = True,\n",
    ")\n",
    "\n",
    "docs = text_splitter.create_documents([state_of_the_union])\n",
    "print(docs[0])\n",
    "print(docs[1])\n",
    "print(type(docs))\n",
    "print(type(docs[0]))\n",
    "metadatas = [{\"document\": 1}, {\"document\": 2}]\n",
    "documents = text_splitter.create_documents([state_of_the_union, state_of_the_union], metadatas=metadatas)\n",
    "print(documents[0])\n",
    "\n",
    "# 支持编程语言的完整列表\n",
    "print([e.value for e in Language])\n",
    "\n",
    "html_text = \"\"\"\n",
    "<!DOCTYPE html>\n",
    "<html>\n",
    "    <head>\n",
    "        <title>🦜️🔗 LangChain</title>\n",
    "        <style>\n",
    "            body {\n",
    "                font-family: Arial, sans-serif;\n",
    "            }\n",
    "            h1 {\n",
    "                color: darkblue;\n",
    "            }\n",
    "        </style>\n",
    "    </head>\n",
    "    <body>\n",
    "        <div>\n",
    "            <h1>🦜️🔗 LangChain</h1>\n",
    "            <p>⚡ Building applications with LLMs through composability ⚡</p>\n",
    "        </div>\n",
    "        <div>\n",
    "            As an open source project in a rapidly developing field, we are extremely open to contributions.\n",
    "        </div>\n",
    "    </body>\n",
    "</html>\n",
    "\"\"\"\n",
    "\n",
    "html_splitter = RecursiveCharacterTextSplitter.from_language(\n",
    "    language=Language.HTML, chunk_size=60, chunk_overlap=0\n",
    ")\n",
    "html_docs = html_splitter.create_documents([html_text])\n",
    "print(len(html_docs))\n",
    "print(html_docs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a7cbf5c-dde5-468b-93dd-b4f2c3ee5520",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
